package languageacquisition;

import java.util.HashSet;
import java.util.Set;

import jade.content.ContentElement;
import jade.content.lang.Codec.CodecException;
import jade.content.onto.OntologyException;
import jade.content.onto.UngroundedException;
import jade.core.behaviours.CyclicBehaviour;
import jade.domain.FIPANames;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import languageacquisition.ontology.Describes;
import languageacquisition.ontology.EnvObject;
import languageacquisition.ontology.HasState;
import languageacquisition.ontology.LanguageOntology;

public class ReactiveSymbolGroundingBehaviour extends CyclicBehaviour {

	private static final long serialVersionUID = -4587901736627060245L;
	private MessageTemplate mt;
	protected PopulationAgent myPopulationAgent;
	protected Set<Describes> learningHistory = new HashSet<Describes>();
	
	public ReactiveSymbolGroundingBehaviour() {
		super();
	}

	public ReactiveSymbolGroundingBehaviour(PopulationAgent a) {
		super(a);
		myPopulationAgent = a;
	}

	@Override
	public void onStart() {
		mt = MessageTemplate.MatchPerformative(ACLMessage.INFORM);
		mt = MessageTemplate.and(mt, MessageTemplate.MatchLanguage(FIPANames.ContentLanguage.FIPA_SL));
		mt = MessageTemplate.and(mt, MessageTemplate.MatchOntology(LanguageOntology.getInstance().getName()));
		mt = MessageTemplate.and(mt, MessageTemplate.not(MessageTemplate.MatchProtocol(FIPANames.InteractionProtocol.FIPA_QUERY)));
	}

	@Override
	public void action() {
		ACLMessage msg = myAgent.receive(mt);
		if (msg != null) {
			System.out.println(myAgent.getLocalName() + ": New msg received.");
			try {
				ContentElement content = myAgent.getContentManager().extractContent(msg);
				final Describes describes;
				if (content instanceof Describes) {
					describes = (Describes) content;	
				} else {
					System.err.println("Content of message not understood. Describes predicate expected.");
					return;
				}
				EnvObject object = describes.getObject();
				HasState curstate = myPopulationAgent.getObservation(describes.getObject());
				
				// if there is no observation about object or observation is outdated
				if (curstate == null || curstate.getTime() < describes.getTime()) {
					myAgent.addBehaviour(new QueryObservationInitiator(myAgent, object.getAid()){
						private static final long serialVersionUID = 7608795763028592089L;

						protected void handleObservation(HasState hasState) {
							myPopulationAgent.updateObservation(hasState);
							analize(describes, hasState);
						}
					});
					System.out.println(myAgent.getLocalName() + ": Observation outdated. Getting new one.");
				} else {
					analize(describes, curstate);
				}
				
			} catch (UngroundedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (CodecException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (OntologyException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}			
		} else {
			block();
		}		
	}

	protected void analize(Describes describes, HasState hasState) {
		if (learningHistory.contains(describes)){
			System.out.println(myAgent.getLocalName() + ": Information was used previously.");
			return;
		}
		// TODO: couse problems
		//learningHistory.add(describes);
		if (describes.getTime() == hasState.getTime()) {
			myPopulationAgent.updateCorrelation(describes.getSymbol(), hasState.getState());
		} else {
			System.out.println(myAgent.getLocalName() + ": Object has already changed.");
		}
	}
}
